package com.example.practiceopenglfortexture;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.opengl.GLSurfaceView;
import android.util.Log;
import android.view.Surface;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;

/**
 * name : TCamera2
 * time : 2019.11.15
 */

class TCamera2 {

    private static final String tag = "_" + "TCamera2";
    // for camera
    private String mCameraId;
    private CameraManager mCameraManager;
    private CameraDevice mCameraDevice;
    private CameraCaptureSession mCaptureSession;
    // for the number of thread
    private Semaphore mCameraOpenCloseLock = new Semaphore(1);
    // for environment
    private Context mContext;
//    private Activity mActivity;
    // for texture
    private GLSurfaceView mSurfaceView;
    private SurfaceTexture mSurfaceTexture;
    private Surface mSurface;

    TCamera2(Context context, GLSurfaceView glSurfaceView) {
        // config camera2
        mContext = context;
        mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);

        mCameraId = "0";
        mSurfaceView = glSurfaceView;
    }

    void stopPreview() {
        // stop preview
        try {
            mCameraOpenCloseLock.acquire();
            if (mCaptureSession != null) {
                mCaptureSession.close();
                mCaptureSession = null;
            }
            if (mCameraDevice != null) {
                mCameraDevice.close();
                mCameraDevice = null;
            }
        } catch (InterruptedException e) {
            Log.e(tag, "request access fail !");
            e.printStackTrace();
        } finally {
            mCameraOpenCloseLock.release();
        }
    }

    void startPreview(SurfaceTexture surfaceTexture) {
        // get SurfaceTexture
        mSurfaceTexture = surfaceTexture;
        // start preview
        try {
            mCameraOpenCloseLock.acquire();
        } catch (InterruptedException e) {
            Log.e(tag, "request access fail !");
            e.printStackTrace();
        }
        try {
            if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                // TODO: Consider calling
                //    Activity#requestPermissions
                // here to request the missing permissions, and then overriding
                //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                //                                          int[] grantResults)
                // to handle the case where the user grants the permission. See the documentation
                // for Activity#requestPermissions for more details.
                Log.e(tag, "request permissions fail !");
                return;
            }
            mCameraManager.openCamera(mCameraId, mStateCallback, null);
        } catch (CameraAccessException e) {
            Log.e(tag, "open camera fail !");
            e.printStackTrace();
        }
    }

    private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice cameraDevice) {
            // create capture session
            mCameraOpenCloseLock.release();
            mCameraDevice = cameraDevice;

            assert mSurfaceTexture != null;
            mSurfaceTexture.setDefaultBufferSize(1280, 720);
            mSurfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
                @Override
                public void onFrameAvailable(SurfaceTexture surfaceTexture) {
                    mSurfaceView.requestRender();
                    Log.d(tag, "surface texture......");
//                    surfaceTexture.updateTexImage();
                }
            });
            mSurface = new Surface(mSurfaceTexture);

            List<Surface> surfaces = new ArrayList<>();
            surfaces.add(mSurface);
            // create capture session
            try {
                mCameraDevice.createCaptureSession(surfaces, mSessionStateCallback, null);
            } catch (CameraAccessException e) {
                Log.e(tag, "create capture session fail !");
                e.printStackTrace();
            }
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice cameraDevice) {
            //
            mCameraOpenCloseLock.release();
            cameraDevice.close();
            cameraDevice = null;
        }

        @Override
        public void onError(@NonNull CameraDevice cameraDevice, int i) {
            //
            mCameraOpenCloseLock.release();
            cameraDevice.close();
            cameraDevice = null;
        }
    };
    private CameraCaptureSession.StateCallback mSessionStateCallback = new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
            // config session
            mCaptureSession = cameraCaptureSession;
            // set repeating request
            try {
                CaptureRequest.Builder mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                mPreviewRequestBuilder.addTarget(mSurface);
                CaptureRequest mPreviewRequest = mPreviewRequestBuilder.build();
                mCaptureSession.setRepeatingRequest(mPreviewRequest, new CameraCaptureSession.CaptureCallback() {
                    @Override
                    public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) {
                        super.onCaptureStarted(session, request, timestamp, frameNumber);
                        // capture start
                    }

                    @Override
                    public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                        super.onCaptureCompleted(session, request, result);
                        // capture complete
                    }
                }, null);
            } catch (CameraAccessException e) {
                Log.e(tag, "create capture request fail !");
                e.printStackTrace();
            }
        }

        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
            // config session fail
        }
    };

}
